package ch.il07.utils.logging;

import java.io.CharArrayWriter;
import java.io.PrintWriter;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Map;
import java.util.WeakHashMap;

public abstract class AbstractLogger implements Logger {

	private final Level level;

	private static final Map<String, DateFormat> dateFormatCache = new WeakHashMap<String, DateFormat>();

	private static final String LOG_PATTERN = "%s [%s] %s\n";

	public AbstractLogger(Level level) {
		this.level = level;
	}

	protected static String getDateTime(String pattern) {
		DateFormat dateFormat;
		if (dateFormatCache.containsKey(pattern)) {
			dateFormat = dateFormatCache.get(pattern);
		} else {
			dateFormat = new SimpleDateFormat(pattern);
			dateFormatCache.put(pattern, dateFormat);
		}
		return dateFormat.format(new Date());
	}

	protected static String format(Level level, String msg, Throwable cause) {
		String dateTime = getDateTime("yyyy-MM-dd HH:mm:ss");
		String firstLine = String.format(LOG_PATTERN, dateTime, level,
				msg == null ? "" : msg);
		if (cause == null) {
			return firstLine;
		}

		StringBuilder sb = new StringBuilder(firstLine);
				
		CharArrayWriter caw = new CharArrayWriter();
		PrintWriter      pw = new PrintWriter (caw);
		cause.printStackTrace(pw);

		return sb.append(caw.toString()).toString();
	}

	@Override
	public boolean isLoggable(Level level) {
		return this.level.isHigher(level);
	}

	@Override
	public void error(String msg, Throwable cause) {
		log(Level.ERROR, msg, cause);
	}

	@Override
	public void error(Throwable cause) {
		error(null, cause);
	}

	@Override
	public void error(String msg) {
		error(msg, null);
	}

	@Override
	public void warning(String msg, Throwable cause) {
		log(Level.WARNING, msg, cause);
	}

	@Override
	public void warning(Throwable cause) {
		warning(null, cause);
	}

	@Override
	public void warning(String msg) {
		warning(msg, null);
	}

	@Override
	public void info(String msg, Throwable cause) {
		log(Level.INFO, msg, cause);
	}

	@Override
	public void info(Throwable cause) {
		info(null, cause);
	}

	@Override
	public void info(String msg) {
		info(msg, null);
	}

	@Override
	public void fine(String msg, Throwable cause) {
		log(Level.FINE, msg, cause);
	}

	@Override
	public void fine(Throwable cause) {
		fine(null, cause);
	}

	@Override
	public void fine(String msg) {
		fine(msg, null);
	}

	@Override
	public void log(Level level, Throwable cause) {
		log(level, null, cause);
	}

	@Override
	public void log(Level level, String msg) {
		log(level, msg, null);
	}
}
